﻿using RazorEngine;
using RazorEngine.Templating;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;

namespace AspNetPaging
{
    public class PagingModel : IValidatableObject, IHtmlString
    {
        public PagingModel(
            int? page = null,
            int? total = null,
            int? size = null,
            int? link = 11,
            string prev = "<<",
            string next = ">>",
            int[] sizes = null,
            string template = null,
            Func<string, object, IHtmlString> render = null)
        {
            Page = page ?? 1;
            Total = total ?? 0;
            Sizes = sizes ?? PagingManager.Sizes;
            DefaultSize = PagingManager.Size;
            Size = size ?? DefaultSize;
            Link = link ?? PagingManager.Link;
            Prev = prev ?? PagingManager.Prev;
            Next = next ?? PagingManager.Next;
            Template = template;
            this.Render = render;
        }

        #region Properties

        [ScaffoldColumn(false)]
        public int Page { get; set; }

        [ScaffoldColumn(false)]
        public int Total { get; set; }

        [ScaffoldColumn(false)]
        public int[] Sizes { get; set; }

        [ScaffoldColumn(false)]
        public int Size { get; set; }

        [ScaffoldColumn(false)]
        public int DefaultSize { get; set; }

        [ScaffoldColumn(false)]
        public int Link { get; set; }

        [ScaffoldColumn(false)]
        public int PageCount { get { return (int)Math.Ceiling(this.Total / (double)this.Size); } }

        [ScaffoldColumn(false)]
        public string Next { get; set; }

        [ScaffoldColumn(false)]
        public string Prev { get; set; }

        [ScaffoldColumn(false)]
        public string Template { get; set; }

        [ScaffoldColumn(false)]
        public Func<string, object, IHtmlString> Render { get; set; }

        [ScaffoldColumn(false)]
        public bool HasPrev
        {
            get { return Page > 1; }
        }

        [ScaffoldColumn(false)]
        public bool HasNext
        {
            get
            {
                return Page < PageCount;
            }
        }

        #endregion Properties

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Sizes.Any(o => o == Size))
            {
                yield return new ValidationResult("Page Size out of defined", new string[] { "Size" });
            }
        }

        public string GetPrevUrl(string url = null)
        {
            return this.GetUrl(Page - 1, url);
        }

        public string GetNextUrl(string url = null)
        {
            return this.GetUrl(Page + 1, url);
        }

        public IEnumerable<int> GetPageIndexs()
        {
            var left = Link / 2;
            var start = Page - left;
            start = start > 1 ? start : 1;
            var end = Page + (Link - left - 1);
            end = end > PageCount ? PageCount : end;
            if (start == 1 && end < PageCount)
            {
                while (end - start + 1 < Link && end < PageCount)
                {
                    end++;
                }
            }
            if (end == PageCount && start > 1)
            {
                while (end - start + 1 < Link && start > 1)
                {
                    start--;
                }
            }
            return this.GetIndexs(start, end);
        }

        private IEnumerable<int> GetIndexs(int start, int end)
        {
            var list = new List<int>();
            for (int i = start; i <= end; i++)
            {
                list.Add(i);
            }
            return list;
        }

        public string GetUrl(int i, string url = null)
        {
            url = url ?? HttpContext.Current.Request.Url.ToString();
            if (i == 1)
            {
                url = url.RemoveParam("Page");
            }
            else
            {
                url = url.SetParam("Page", i.ToString());
            }
            url = url.RemoveParam("Size", Size == DefaultSize);
            url = url.RemoveNullOrEmptyParam();
            return url;
        }

        public string ToHtmlString()
        {
            if (this.Render != null && !string.IsNullOrEmpty(this.Template))
            {
                return this.Render(Template, this).ToHtmlString();
            }
            string name = string.IsNullOrEmpty(Template) ? "default" : Template;
            using (TextReader reader = new StreamReader(Assembly.GetAssembly(typeof(PagingModel)).GetManifestResourceStream(string.Format("AspNetPaging.Views.{0}.cshtml",name))))
            {
                string template = reader.ReadToEnd();
                return Engine.Razor.RunCompile(template,name, typeof(PagingModel), this);
            }
        }
    }
}